//
//  YLAESTool.swift
//  YLIMKeyBoard
//
//  Created by AlbertYuan on 2022/12/29.
//

import Foundation
import CryptoSwift

///数据加解密错误
public enum YLAESToolError:Error{
    case dataParseError //数据解析失败

    case encryptError //加密失败

    case decryptError //解密失败
}


///秘钥类型
public enum YLAESToolSecretkeyType{
    case buildIn //内置秘钥

    case http //服务器获取的http秘钥

    case ws //服务器获取的ws秘钥
}

public class YLAESTool:NSObject{

    ///完成回调
    public typealias completeClosure = (_ response:Any?)->()

    ///这里根据业务需要可自行修改：iv只有在特定模式下才会使用
    ///static var gIv:String = "0123456776543210"
    ///内置的秘钥
    static public var buildinSecretKey:String = "c0bd8b321189793c536becb107b45d1d"
    ///通过服务器获取的HTTP秘钥
    static public var httpSecretkey:String = ""
    ///通过服务器获取的ws秘钥
    static public var wsSecreykey:String = ""


    static public let share = YLAESTool.init()
    private override init(){}

    /// 秘钥更新
    /// - Parameters:
    ///   - newHttpKey: 新的HTTP秘钥
    ///   - newWsKey: 新的ws秘钥
    static public func updateSecretKey(newHttpKey:String? = nil, newWsKey:String? = nil){
        if let newHttpKey = newHttpKey{
            httpSecretkey = newHttpKey
        }
        if let newWsKey = newWsKey {
            wsSecreykey = newWsKey
        }
    }

    /// 更具请求方式获取对应的key值
    /// - Parameter secretType: 秘钥处理方式  默认是获取的http秘钥
    /// - Returns: 秘钥
    private static func getSecretKey(secretType:YLAESToolSecretkeyType = .http)->String { 
        switch secretType {
        case .buildIn:
            return buildinSecretKey
        case .http:
            return httpSecretkey
        case .ws:
            return wsSecreykey
        }
    }
}

extension YLAESTool{

    //根据随机数据更新请求秘钥
    static public func resettingEncryptSecretKey(req_id:String,
                                          req_time:String,
                                          secretType:YLAESToolSecretkeyType = .http) -> String?{
        let  oringSecret = getSecretKey(secretType: secretType)

        if oringSecret == ""{
            return nil
        }

        let  dataArr = [oringSecret,req_id,req_time]
        let encrptString = dataArr.joined(separator: "*")
        let res = encrptString.md5()
        return res
    }


    //根据随机数据更新响应秘钥
    static public func resettingDecrptSecretkey(req_time:String,
                                         app_ver:String,
                                         req_id:String,
                                         sb_bs:String,
                                         sb_lx:String,
                                         secretType:YLAESToolSecretkeyType = .http) ->String?{

        let  oringSecret = getSecretKey(secretType: secretType)
        if oringSecret == ""{
            return nil
        }

        let  dataArr = [req_time,app_ver,req_id,sb_bs,oringSecret,sb_lx]
        let encrptString = dataArr.joined(separator: "*#*")
        let res = encrptString.md5()
        return res
    }

}


//加密
public extension YLAESTool{

    @discardableResult
    /// aes加密方法dic格式
    /// - Parameters:
    ///   - originDic: 原始数据dic格式
    ///   - secret: 秘钥处理方式 外部传入的秘钥
    ///   - base64: 是否对结果进行base64处理 默认是
    /// - Returns: 加密结果
    static func AES_EncryptDictionary(originDic:[String:Any],
                                      secret:String,
                                      base64:Bool = true,
                                      complete:completeClosure? = nil) -> Any? {

        //sortedKeys排序：升序
        guard let dataInfo = try? JSONSerialization.data(withJSONObject: originDic,options: [.sortedKeys]) else{
            debugPrint("数据转换失败")

            complete?(nil)
            return nil
        }

        let res =  AES_Encrypt(data: dataInfo,secret: secret,base64: base64)
        complete?(res)
        return res

    }


    @discardableResult
    /// aes加密方法string格式
    /// - Parameters:
    ///   - originString: 原始数据dic格式
    ///   - secret: 秘钥处理方式 外部传入的秘钥
    ///   - base64: 是否对结果进行base64处理 默认是
    /// - Returns: 加密结果
    static func AES_EncryptString(originString:String,
                                      secret:String,
                                      base64:Bool = true,
                                      complete:completeClosure? = nil) -> Any?{

        //sortedKeys排序：升序
        guard let data = originString.data(using: .utf8) else{
            debugPrint("字符串数据转换失败")
            complete?(nil)
            return nil
        }

        let res =  AES_Encrypt(data: data,secret: secret,base64: base64)
        complete?(res)
        return res

    }


    @discardableResult
    /// aes加密方法data格式
    /// - Parameter originData: 原始数据data格式
    /// - Parameter secretType: 秘钥处理方式  默认是获取的http秘钥
    /// - Parameter：base64：是否直接将结果转换为base64字符串
    /// - Parameter：complete：加密数据回调
    /// - Returns: 加密数据
    static func AES_EncryptData(originData:Data,
                                secret:String,
                                base64:Bool = true,
                                complete:completeClosure? = nil)-> Any?{

        //sortedKeys排序 ,options: [.sortedKeys]
        guard let dic = try? JSONSerialization.jsonObject(with: originData) as? [String:Any],
              let dataInfo = try? JSONSerialization.data(withJSONObject: dic,options: [.sortedKeys]) else{
            debugPrint("AES 加密：数据解析失败")
            complete?(nil)
            return nil
        }

        let res =  AES_Encrypt(data: dataInfo,secret: secret, base64:base64)
        complete?(res)
        return res

    }



    @discardableResult
    /// aes加密内部加密方法
    /// - Parameters:
    ///   - data: 原始data数据
    ///   - base64:是否对结果进行base64处理 默认是
    /// - Returns: 加密结果
    private static func AES_Encrypt(data:Data,
                                    secret:String,
                                    base64:Bool = true,
                                    complete:completeClosure? = nil)->Any?{
        if secret == ""{
            debugPrint("秘钥不能为空")
            complete?(nil)
            return nil
        }

        do{
            let aes = try  AES(key: secret.bytes, blockMode: ECB())
            let encryptedBytes = try aes.encrypt(data.bytes)
            let encryptedData = Data(encryptedBytes)

            if base64{
                let res =  base64_Encryp(originData: encryptedData)
                complete?(res)
                return res
            }
            else{
                complete?(encryptedData)
                return encryptedData
            }
        }
        catch{
            debugPrint("加密失败:\(error)")
            complete?(nil)
            return nil
        }
    }


    @discardableResult
    /// base64加密
    /// - Parameter originData: 原始数据
    /// - Returns: 加密数据
    static func base64_Encryp(originData:Data,
                              complete:completeClosure? = nil)->String{
            let res = originData.bytes.toBase64()
            complete?(res)
            return res
    }
}

//解密
public extension YLAESTool{


    @discardableResult
    /// aes解密方法：直接将base64数据解密
    /// - Parameter originData: 原始数据base64字符串
    /// - Returns: 解密数据
    static func AES_DecryptBase64(originData:String,
                                  secret:String,
                                  complete:completeClosure? = nil)->Any?{

        do{
            let cipher = try AES(key: secret.bytes, blockMode: ECB())
            let bytestring = try originData.decryptBase64ToString(cipher: cipher)
            guard JSONSerialization.isValidJSONObject(bytestring) else{
                complete?(bytestring)
                return bytestring
            }

            if let data = bytestring.data(using: .utf8),
                let res = try? JSONSerialization.jsonObject(with: data) as? [String:Any]{
                complete?(res)
                return res
            }

            debugPrint("AES解密base64数据解析失败")
            complete?(nil)
            return nil

        }catch{

            debugPrint("AES解密base64失败:\(error)")
            complete?(nil)
            return nil
        }
    }



    @discardableResult
    /// aes解密方法：直接将data解密
    /// - Parameter originData: 原始data数据
    /// - Returns: 解密后的数据
    static func AES_DecryptData(originData:Data,
                                secret:String,
                                complete:completeClosure? = nil)->Data?{
        do{

            let aes = try  AES(key: secret.bytes, blockMode: ECB())
            let bytes = try aes.decrypt(originData.bytes)
            let res = Data(bytes)
            complete?(res)
            return res

        }catch{

            debugPrint("AES解密Data失败:\(error)")
            complete?(nil)
            return nil
        }
    }

}


// MARK: -- 数据解析
public extension YLAESTool{

    /// data数据JSON解析
    /// - Parameters:
    ///   - originData: 原始data数据
    ///   - complete: 回调信息
    /// - Returns: 解析过的数据
    static func dataJSONMap(originData:Data,
                            complete:completeClosure? = nil)->[String:Any]?{



        do{

            if let res = try JSONSerialization.jsonObject(with: originData) as? [String:Any]{
                complete?(res)
                return res
            }

            complete?(nil)
            return nil

        }catch{

            debugPrint("JSON解析失败:\(error)")
            complete?(nil)
            return nil
        }
    }

}

